#ifndef __IR_H__
#define __IR_H__


#include <string>
#include <vector>

#include <boost/shared_ptr.hpp>

using namespace boost;
namespace Temp {
	struct Temp;
	struct Label;
	struct LabelList;
}

namespace Tree {

struct Exp;
struct Stm;

enum BinaryOperation {
	Plus = 0,
	Minus,
	Times,
	And,
	Or
};

enum CJumpOperation {
	Equal = 0,
	NotEqual,
	LessThan,
	GreaterThan
};

struct Exp {
	Exp();	

};

struct ExpList {
	ExpList(shared_ptr<Exp> head, shared_ptr<ExpList> tail);

	shared_ptr<Exp> head;
	shared_ptr<ExpList> tail;
};

struct Const : public Exp {
	Const(const int value);
	
	int value;
};

struct Name : public Exp {
	Name(shared_ptr<Temp::Label> label);

	shared_ptr<Temp::Label> label;
};

struct TempExp : public Exp {
	TempExp(shared_ptr<Temp::Temp> temp);

	shared_ptr<Temp::Temp> temp;
};

struct Binop : public Exp {
	Binop(BinaryOperation binop, shared_ptr<Exp> left, shared_ptr<Exp> right);

	BinaryOperation binop;
	shared_ptr<Exp> left;
	shared_ptr<Exp> right;
};

struct Mem : public Exp {
	Mem(shared_ptr<Exp> exp);

	shared_ptr<Exp> exp;
};

struct Call : public Exp {
	Call(shared_ptr<Exp> func, shared_ptr<ExpList> args);

	shared_ptr<Exp> func;
	shared_ptr<ExpList> args;
};

struct ESeq : public Exp {
	ESeq(shared_ptr<Stm> stm, shared_ptr<Exp> exp);

	shared_ptr<Stm> stm;
	shared_ptr<Exp> exp;
};

struct Stm {
	Stm();
};

struct StmList {
	StmList(shared_ptr<Stm> head, shared_ptr<StmList> tail);

	shared_ptr<Stm> head;
	shared_ptr<StmList> tail;
};

struct Move : public Stm {
	Move(shared_ptr<Exp> dst, shared_ptr<Exp> src);

	shared_ptr<Exp> dst;
	shared_ptr<Exp> src;
};

struct ExpStm : public Stm {
	ExpStm(shared_ptr<Exp> exp);

	shared_ptr<Exp> exp;
};

struct Jump : public Stm {
	Jump(shared_ptr<Exp> exp, shared_ptr<Temp::LabelList> targets);

	shared_ptr<Exp> exp;
	shared_ptr<Temp::LabelList> targets;
};

struct CJump : public Stm {
	CJump(CJumpOperation op, shared_ptr<Exp> left, shared_ptr<Exp> right, shared_ptr<Temp::Label> iftrue, shared_ptr<Temp::Label> iffalse);

	CJumpOperation op;
	shared_ptr<Exp> left;
	shared_ptr<Exp> right;
	shared_ptr<Temp::Label> iftrue;
	shared_ptr<Temp::Label> iffalse;
};

struct Seq : public Stm {
	Seq(shared_ptr<Stm> left, shared_ptr<Stm> right);

	shared_ptr<Stm> left;
	shared_ptr<Stm> right;
};

struct StmLabel : public Stm {
	StmLabel(shared_ptr<Temp::Label> label);

	shared_ptr<Temp::Label> label;
};

}

#endif

